package org.hilo.boot.core.dubbo;

import org.jretty.util.JrettyCache;
import org.slf4j.Logger;

import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;

import org.hilo.boot.core.BaseMsg;
import org.hilo.boot.core.UT;

/**
 * 
 * @author zollty
 * @since 2020年6月10日
 */
public abstract class AbstractFilterService {

    // 5000 - 5秒钟内重复异常不记录
    protected JrettyCache cache = new JrettyCache(128, 5000);
    protected static final String STRING_LEN0 = "";
    protected final Logger logger;
    
    static boolean metricsAvailable;
    static {
        try {
            metricsAvailable = null != Class.forName("io.micrometer.core.instrument.Metrics");
        } catch (Throwable t) {
            metricsAvailable = false;
        }
    }

    public AbstractFilterService(Logger logger) {
        this.logger = logger;
    }
    
    protected StringBuilder assembleBaseInfo(Invoker<?> invoker, Invocation inv, String remoteHost,
            Long startTime) {
        Long takeTime = System.currentTimeMillis() - startTime;
        String serviceName = invoker.getInterface().getName();
        String version = invoker.getUrl().getParameter(Constants.VERSION_KEY);
        String group = invoker.getUrl().getParameter(Constants.GROUP_KEY);
        StringBuilder sn = new StringBuilder();
        sn.append("remote host: ").append(remoteHost).append(" - ");
        if (null != group && group.length() > 0) {
            sn.append(group).append("/");
        }
        sn.append(serviceName);
        if (null != version && version.length() > 0) {
            sn.append(":").append(version);
        }
        sn.append(" ");
        sn.append(inv.getMethodName());
        Object[] args = inv.getArguments();
        if (args != null && args.length > 0) {
            sn.append("(").append(UT.Json.toJSONString(args.length == 1 ? args[0] : args)).append(")");
        } else {
            sn.append("()");
        }
        sn.append(", cost ").append(takeTime).append("ms");
        return sn;
    }
    
    protected void recordMetricsSuccess(boolean consumer, Invoker<?> invoker, Invocation inv,
            String remoteHost, long start) {
        recordMetrics(consumer, invoker, inv, remoteHost, start, BaseMsg.SUCCESS.name(),
                BaseMsg.SUCCESS.getCode());
    }
    
    protected void recordMetrics(boolean consumer, Invoker<?> invoker, Invocation inv,
            String remoteHost, long start, String outcome, String errorCode) {
        if (metricsAvailable) {
            DubboMetricsTools.collect(consumer, invoker, inv, remoteHost, start, outcome,
                    errorCode);
        }
    }
    
    protected void checkAndLog(Invoker<?> invoker, Invocation inv, String remoteHost,
            Long startTime, String key, String code, String msg) {

        if (cache.putIfAbsent(key, code)) {
            StringBuilder sn = assembleBaseInfo(invoker, inv, remoteHost, startTime);
            sn.insert(0, "error: ");
            sn.append(": \r\n").append(code).append(": ").append(msg);

            logger.error(sn.toString());
        }
    }

    protected void traceException(Invoker<?> invoker, Invocation inv, String remoteHost,
            Long startTime, String code, String msg) {
        StringBuilder sn = assembleBaseInfo(invoker, inv, remoteHost, startTime);
        sn.insert(0, "error: ");
        sn.append(": \r\n").append(code).append(": ").append(msg);
        logger.info(sn.toString());
    }

    protected void traceNormal(Invoker<?> invoker, Invocation inv, String remoteHost,
            Long startTime, Result result) {
        StringBuilder sn = assembleBaseInfo(invoker, inv, remoteHost, startTime);
        sn.insert(0, "success: ");
        sn.append(", return: ").append(UT.Json.toJSONString(result.getValue()));
        logger.info(sn.toString());
    }
}
